package cn.schoolwow.quickapi.module.business.apiParameter.service;

import cn.schoolwow.ams.domain.option.QuickAMSOption;
import cn.schoolwow.quickapi.domain.QuickAPIOption;
import cn.schoolwow.quickapi.module.business.api.domain.API;
import cn.schoolwow.quickapi.module.business.apiParameter.domain.APIParameter;
import cn.schoolwow.quickapi.module.business.apiParameter.flow.header.GetRequestHeaderAnnotationFlow;
import cn.schoolwow.quickapi.module.business.apiParameter.flow.parameter.*;
import cn.schoolwow.quickapi.module.common.domain.APIDocument;
import cn.schoolwow.quickapi.module.common.flow.GetGenericTypeRecycleClassNameFlow;
import cn.schoolwow.quickapi.module.common.flow.GetRecycleClassNameFlow;
import cn.schoolwow.quickapi.util.QuickAPIUtil;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;

import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SetAPIParameterListFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        setAPIParameterList(flowContext);
        setParameterEntity(flowContext);
        setAPIType(flowContext);
        executeAPIParameterListener(flowContext);
    }

    @Override
    public String name() {
        return "设置API参数列表复合流程";
    }

    private void setAPIParameterList(FlowContext flowContext) throws Exception{
        APIDocument apiDocument = flowContext.checkInstanceData(APIDocument.class);
        JavaProjectBuilder javaProjectBuilder = flowContext.getInstanceData(JavaProjectBuilder.class);

        for(API api:apiDocument.apiList){
            List<String> parameterNameList = new ArrayList<>();

            if(null!=javaProjectBuilder){
                JavaClass javaClass = javaProjectBuilder.getClassByName(api.apiController.className);
                List<JavaMethod> javaMethodList = javaClass.getMethods();
                for(JavaMethod javaMethod:javaMethodList) {
                    if (javaMethod.getModifiers().contains("public")&&javaMethod.getName().equalsIgnoreCase(api.method.getName())) {
                        List<JavaParameter> javaParameterList = javaMethod.getParameters();
                        for(JavaParameter javaParameter:javaParameterList){
                            parameterNameList.add(javaParameter.getName());
                        }
                        break;
                    }
                }
            }

            //方法参数
            Parameter[] parameters = api.method.getParameters();

            StringBuilder queryBuilder = new StringBuilder();
            StringBuilder requestBodyBuilder = new StringBuilder();
            for(int i=0;i<parameters.length;i++){
                Parameter parameter = parameters[i];

                APIParameter apiParameter = new APIParameter();
                apiParameter.name = parameter.getName();
                if(!parameterNameList.isEmpty()){
                    apiParameter.name = parameterNameList.get(i);
                }
                apiParameter.parameter = parameter;
                apiParameter.api = api;

                String parameterRawName = apiParameter.name;

                flowContext.startFlow(new GetRequestHeaderAnnotationFlow())
                        .putCurrentCompositeFlowData("parameterRawName", parameterRawName)
                        .putCurrentCompositeFlowData("apiParameter", apiParameter)
                        .putCurrentCompositeFlowData("parameter", parameter)
                        .putCurrentCompositeFlowData("api", api)
                        .execute();
                if(flowContext.containKey("finished")){
                    continue;
                }

                queryBuilder.setLength(0);
                flowContext.startFlow(new GetByPathVariableAnnotationFlow())
                        .next(new GetByRequestParamAnnotationFlow())
                        .next(new GetByRequestBodyAnnotationFlow())
                        .next(new GetByRequestPartAnnotationFlow())
                        .next(new GetByAPIParameterFunctionFlow())
                        .putCurrentCompositeFlowData("queryBuilder", queryBuilder)
                        .putCurrentCompositeFlowData("requestBodyBuilder", requestBodyBuilder)
                        .putCurrentCompositeFlowData("parameterRawName", parameterRawName)
                        .putCurrentCompositeFlowData("apiParameter", apiParameter)
                        .putCurrentCompositeFlowData("parameter", parameter)
                        .putCurrentCompositeFlowData("api", api)
                        .execute();
                api.apiParameterList.add(apiParameter);
            }
            if(queryBuilder.length()>0){
                if(queryBuilder.charAt(queryBuilder.length()-1)=='&'){
                    queryBuilder.deleteCharAt(queryBuilder.length()-1);
                }
                api.url += "?"+queryBuilder.toString();
            }
            if(requestBodyBuilder.length()>0){
                if(requestBodyBuilder.charAt(requestBodyBuilder.length()-1)=='&'){
                    requestBodyBuilder.deleteCharAt(requestBodyBuilder.length()-1);
                }
            }
            api.requestBody = requestBodyBuilder.toString();
            api.requestBody = QuickAPIUtil.formatAndPrettyJSON(api.requestBody);
        }
    }

    private void setParameterEntity(FlowContext flowContext){
        APIDocument apiDocument = flowContext.checkInstanceData(APIDocument.class);

        for(API api:apiDocument.apiList){
            for(APIParameter apiParameter:api.apiParameterList){
                flowContext.startFlow(new GetRecycleClassNameFlow())
                        .next(new GetGenericTypeRecycleClassNameFlow())
                        .putCurrentCompositeFlowData("rootClazz", apiParameter.parameter.getType())
                        .putCurrentCompositeFlowData("rootType", apiParameter.parameter.getType())
                        .putCurrentCompositeFlowData("classNameSet", api.parameterEntityNameList)
                        .execute();
            }
        }
    }

    private void setAPIType(FlowContext flowContext){
        APIDocument apiDocument = flowContext.checkInstanceData(APIDocument.class);
        QuickAMSOption quickAMSOption = flowContext.checkInstanceData(QuickAMSOption.class);

        if (quickAMSOption.packageNameLabelMap.isEmpty()) {
            return;
        }

        for(API api:apiDocument.apiList){
            String className = api.method.getDeclaringClass().getName();
            for(Map.Entry<String,String> entry:quickAMSOption.packageNameLabelMap.entrySet()){
                if(className.contains(entry.getKey())){
                    api.type = entry.getValue();
                }
            }
            if(null==api.type){
                api.type = "其他";
            }
        }
    }

    private void executeAPIParameterListener(FlowContext flowContext){
        QuickAPIOption quickAPIOption = flowContext.checkInstanceData(QuickAPIOption.class);

        if(null==quickAPIOption.apiParameterListener){
            return;
        }
        APIDocument apiDocument = flowContext.checkInstanceData(APIDocument.class);
        for(API api:apiDocument.apiList){
            quickAPIOption.apiListener.handleAPI(api);
        }
    }
}
